Converting geo coordinates from degree to decimal

I want to convert my geographic coordinates from degrees to decimals, my data are as follows:

         lat     long
105252 30°25.264 9°01.331
105253 30°39.237 8°10.811
105255 31°37.760 8°06.040
105258 31°41.190 8°06.557
105259 31°41.229 8°06.622
105260 31°38.891 8°06.281

Try using the char2dms function in the sp library. It has other functions that will additionally do decimal conversion.

library("sp")
?char2dms

A bit of vectorization and matrix manipulation will make your function much simpler:

x <- read.table(text="
       lat     long
105252 30°25.264 9°01.331
105253 30°39.237 8°10.811
105255 31°37.760 8°06.040
105258 31°41.190 8°06.557
105259 31°41.229 8°06.622
105260 31°38.891 8°06.281",
                header=TRUE, stringsAsFactors=FALSE)

x

The function itself makes use of:

Try this:

convert<-function(x){
  z <- sapply((strsplit(x, "[°\\.]")), as.numeric)
  z[1, ] + z[2, ]/60 + z[3, ]/3600
} 

Try it:

convert(x$long)
[1] 9.108611 8.391944 8.111111 8.254722 8.272778 8.178056

Disclaimer: I didn't check your math. Use at your own discretion.

Use the birk package from CRAN which has a unit conversion function already so you don't need to make your own:

x = read.table(text = "
   lat     long
105252 30°25.264 9°01.331
105253 30°39.237 8°10.811
105255 31°37.760 8°06.040
105258 31°41.190 8°06.557
105259 31°41.229 8°06.622
105260 31°38.891 8°06.281",
header = TRUE, stringsAsFactors = FALSE)

Once your data.frame is set up then:

# change the degree symbol to a space
x$lat = gsub('°', ' ', x$lat)
x$long = gsub('°', ' ', x$long)

# convert from decimal minutes to decimal degrees
x$lat = birk::conv_unit(x$lat, from = 'deg_dec_min', to = 'dec_deg')
x$long = birk::conv_unit(x$long, from = 'deg_dec_min', to = 'dec_deg')

Resulting in the end product:

                    lat             long
105252 30.4210666666667 9.02218333333333
105253         30.65395 8.18018333333333
105255 31.6293333333333 8.10066666666667
105258          31.6865 8.10928333333333
105259         31.68715 8.11036666666667
105260 31.6481833333333 8.10468333333333

As Jim Lewis commented before it seems your are using floating point minutes. Then you only concatenate two elements on

dec=c(as.numeric(tmp1[[1]][1]),as.numeric(tmp2[[1]]))

Having degrees, minutes and seconds in the form 43°21'8.02 which as.character() returns "43°21'8.02\"", I updated your function to

convert<-function(coord){
  tmp1=strsplit(coord,"°")
  tmp2=strsplit(tmp1[[1]][2],"'")
  tmp3=strsplit(tmp2[[1]][2],"\"")
  dec=c(as.numeric(tmp1[[1]][1]),as.numeric(tmp2[[1]][1]),as.numeric(tmp3[[1]]))
  c<-abs(dec[1])+dec[2]/60+dec[3]/3600
  c<-ifelse(dec[1]<0,-c,c)
  return(c)
}

adding the alternative for negative coordinates, and works great for me . I still don't get why char2dms function in the sp library didn't work for me.

Another less elegant option using substring instead of strsplit. This will only work if all your positions have the same number of digits. For negative co-ordinates just multiply by -1 for the correct decimal degree.

x$LatDD<-(as.numeric(substring(x$lat, 1,2))
+ (as.numeric(substring(x$lat, 4,9))/60))
x$LongDD<-(as.numeric(substring(x$long, 1,1))
       + (as.numeric(substring(x$long, 3,8))/60))


Coerce to character first.  Here is how you could do it with the DMS data in a data frame:

> m  ## an example with 3 entries
        DMS
1 122:45:45
2 122:45:45
3 122:45:45
> m <- within(m, {
+ dms <- do.call(rbind, strsplit(as.character(DMS), ":"))
+ dec <- as.numeric(dms[,1]) + 
+   (as.numeric(dms[,2]) + as.numeric(dms[,3])/60)/60
+ rm(dms)
+ })
> m
        DMS      dec
1 122:45:45 122.7625
2 122:45:45 122.7625
3 122:45:45 122.7625
> 

m$dec is then the required decimal degrees.